﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace CommonModel.Util
{
    //转换函数
    public class TransForm
    {
        //字符串编码
        public static string encode = "GB2312";

        //读取台站转发站名-编码
        public static string GetStationCode(byte[] tmpBt)
        {
            //用户自定义编码
            string station_code = Encoding.GetEncoding("utf-8").GetString(tmpBt, 0, tmpBt.Length).ToString();
            station_code = station_code.Substring(0, station_code.IndexOf('\0') > 0 ? station_code.IndexOf('\0') : station_code.Length).Replace("\0", " ").Replace(" ", " ").Trim();
            station_code = station_code.Replace(" ", "");
            return station_code;
        }

        //字节转年月日时分秒：按实际取值（采用GMT+8作为时间基准），第一二字节表示年，第三字节表示月，第四字节表示日，第五字节表示小时，第六字节表示分钟，第七字节表示秒
        public static string ByteToDate(byte[] data)
        {
            byte[] y1 = data.Skip(0).Take(1).ToArray();
            byte[] y2 = data.Skip(1).Take(1).ToArray();
            byte[] yearb = new byte[2];
            Buffer.BlockCopy(y1, 0, yearb, 0, y1.Length);//这种方法仅适用于字节数组
            Buffer.BlockCopy(y2, 0, yearb, y1.Length, y2.Length);//将前面两个字节对调
            byte[] monthb= data.Skip(2).Take(1).ToArray();
            byte[] dayb= data.Skip(3).Take(1).ToArray();
            string year = HexChar2Value(ByteToHexString(yearb)).ToString();
            string month = HexChar2Value(ByteToHexString(monthb)).ToString();
            string day = HexChar2Value(ByteToHexString(dayb)).ToString();

            if (data.Length > 4)
            {
                byte[] hourb = data.Skip(4).Take(1).ToArray();
                byte[] minuteb = data.Skip(5).Take(1).ToArray();
                byte[] secondb = data.Skip(6).Take(1).ToArray();
                string hour = HexChar2Value(ByteToHexString(hourb)).ToString();
                string minute = HexChar2Value(ByteToHexString(minuteb)).ToString();
                string second = HexChar2Value(ByteToHexString(secondb)).ToString();
                return year + "/" + month + "/" + day + "/" + hour + ":" + minute + ":" + second;
            }
            return year + "/" + month + "/" + day;
        }

        //十六进制字符串转为十进制
        public static int HexChar2Value(string a)
        {
            a = a.Replace("0x", "");
            int b = Int32.Parse(a, System.Globalization.NumberStyles.HexNumber);
            return b;
        }

        //字节转时分秒：按实际取值，第一字节表示小时，第二字节表示分钟，第三字节表秒
        public static string ByteToDateShort(byte[] data) 
        {
            byte[] hourb = data.Skip(0).Take(1).ToArray();
            byte[] minuteb = data.Skip(1).Take(1).ToArray();
            byte[] secondb = data.Skip(2).Take(1).ToArray();
            string hour = HexChar2Value(ByteToHexString(hourb)).ToString();
            string minute = HexChar2Value(ByteToHexString(minuteb)).ToString();
            string second = HexChar2Value(ByteToHexString(secondb)).ToString();
            return  hour + ":" + minute + ":" + second;
        }

        /**
        * 字节转成十六进制, 原始字节串: 高位在前, 低位在后<br>
        * 即以 BigEndian 方式读取并解析字节串<br/>
        *
        * @param data: 二进制字节串
        * @return 二进制字节串对应的十六进制字符串
        */
        public static string ByteToHexStringBigEndian(byte[] data)
        {
            Array.Reverse(data);//高低位转换
            StringBuilder stringBuilder = new StringBuilder();

            if (data == null || data.Length <= 0)
            {
                return null;
            }

            byte datum;
            for (int m = 0; m < data.Length; m++)
            {
                datum = data[m];
                int v = datum & 0xFF;
                string hv = Convert.ToString(v, 16);
                if (hv.Length< 2)
                {
                    stringBuilder.Append(0);
                }
                stringBuilder.Append(hv);
            }

            return stringBuilder.ToString();
        }

        /**
        * 字节转成十六进制, 原始字节串: 低位在前, 高位在后<br>
        * 即以 小端 方式读取并解析字节串<br/>
        *
        * @param data: 二进制字节串
        * @return 二进制字节串对应的十六进制字符串
        */
        public static string ByteToHexString(byte[] data)
        {
            StringBuilder stringBuilder = new StringBuilder();

            if (data == null || data.Length <= 0)
            {
                return null;
            }

            stringBuilder.Append("0x");
            for (int i = data.Length - 1; i >= 0; i--)
            {
                int v = data[i] & 0xFF;
                string hv = Convert.ToString(v, 16);
                if (hv.Length < 2)
                {
                    stringBuilder.Append(0);
                }
                stringBuilder.Append(hv);
            }
            return stringBuilder.ToString();
        }

        /*
         * 将16进制字符串转换成byte数组
         * hexString 16进制字符串
         * isInv 是否倒置输出
         */
        public static byte[] HexToByte(string hexString, bool isInv)
        {
            hexString = hexString.Replace("0x", "").Replace("0X", "");
            hexString = hexString.Replace(" ", "").Replace("-", "").Replace(":", "").Replace(",", "").Replace("，", "");
            if ((hexString.Length % 2) != 0)
            {
                hexString += " ";
            }
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
            {
                //returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
                returnBytes[isInv ? (returnBytes.Length - i - 1) : i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
            }
            return returnBytes;
            
        }

         //字节数组转字符串，8位，一个字节
        public static string ByteToString(byte[] bytes)
        {
            /*Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//在使用编码方法（Encoding.GetEncoding("GB2312")）之前，对编码进行注册
            string strResult = Encoding.GetEncoding(TransForm.encode).GetString(bytes, 0, bytes.Length).ToString();*/
            string strResult = string.Empty;
            string strTemp;
            for (int i = 0; i < bytes.Length; i++)
            {
                strTemp = System.Convert.ToString(bytes[i], 2);
                strTemp = strTemp.Insert(0, new string('0', 8 - strTemp.Length));
                strResult += strTemp;
            }
            /*
             * 官方定义了XML的无效字符分为三段：<br/>
             * 0x00 - 0x08<br/>
             * 0x0b - 0x0c<br/>
             * 0x0e - 0x1f<br/>
             * 这些字符即使放在CDATA中仍然解析不了，所以最好的办法是过滤掉
             */
            strResult = Regex.Replace(strResult, "[\\x00-\\x08]", "");
            strResult = Regex.Replace(strResult, "[\\x0b-\\x0c]", "");
            strResult = Regex.Replace(strResult, "[\\x0e-\\x1f]", "");

            return strResult;
        }

        //字节数组转字符串UTF8，8位，一个字节
        public static string ByteToStringUTF8(byte[] bytes)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//在使用编码方法（Encoding.GetEncoding("GB2312")）之前，对编码进行注册
            string strResult = Encoding.GetEncoding(TransForm.encode).GetString(bytes, 0, bytes.Length).ToString();

            /*
             * 官方定义了XML的无效字符分为三段：<br/>
             * 0x00 - 0x08<br/>
             * 0x0b - 0x0c<br/>
             * 0x0e - 0x1f<br/>
             * 这些字符即使放在CDATA中仍然解析不了，所以最好的办法是过滤掉
             */
            strResult = Regex.Replace(strResult, "[\\x00-\\x08]", "");
            strResult = Regex.Replace(strResult, "[\\x0b-\\x0c]", "");
            strResult = Regex.Replace(strResult, "[\\x0e-\\x1f]", "");
            strResult = strResult.Replace("<", "");
            strResult = strResult.Replace("?", "");
            strResult = strResult.Replace("€", "");
            return strResult;
        }


        //字节数组转成float浮点数,C#默认是小端存储。long 数据类型是64位、有符号的以二进制补码表示的整数，占8字节
        public static float ByteToFloat(byte[] bytes)
        {
            float fTemp = BitConverter.ToSingle(bytes, 0);
            return fTemp;
        }

        //字节数组转成float，大端存储  ldc 20210506
        public static float ByteToFloatBigEndian(byte[] bytes)
        {
            Array.Reverse(bytes);//翻转高低位
            float fTemp = BitConverter.ToSingle(bytes, 0);
            return fTemp;
        }

        //字节数组转double ，默认小端 ldc 20210506
        public static double ByteToDouble(byte[] data)
        {
            double value = BitConverter.ToDouble(data, 0);
            return value;
        }

        //字节数组转double ，大端 ldc 20210506
        public static double ByteToDoubleBigEndian(byte[] data)
        {
            Array.Reverse(data);//翻转高低位
            double value = BitConverter.ToDouble(data, 0);
            return value;
        }

        //字节数组转32位int，小端，data是四个字节，转换与IntToByteArray配合使用
        public static int ByteToInt(byte[] data)
        {
            int value = BitConverter.ToInt32(data, 0);
            return value;
        }

        //字节转int ,大端 ldc 
        public static int ByteToIntBigEndian(byte[] data)
        {
            Array.Reverse(data);
            int value = BitConverter.ToInt32(data, 0);
            return value;
        }

        //int转字节数组，大端，ldc 20210506
        public static byte[] IntToByteBigEndian(int data)
        {
            byte[] value = BitConverter.GetBytes(data);
            Array.Reverse(value);
            return value;
        }

        //int转字节数组，默认小端，ldc 20210506
        public static byte[] IntToByte(int data)
        {
            byte[] value = BitConverter.GetBytes(data);
            return value;
        }

         //字节数组转long，默认小端
        public static long ByteToLong(byte[] data)
        {
            long value = BitConverter.ToInt64(data, 0);
            return value;
        }

        //字节数组转long，大端，ldc 20210506
        public static long ByteToLongBigEndian(byte[] data)
        {
            Array.Reverse(data);
            long value = BitConverter.ToInt64(data, 0);
            return value;
        }

        //long转字节数组，大端，ldc 20210506
        public static byte[] LongToByteBigEndian(long data)
        {
            byte[] value=BitConverter.GetBytes(data);
            Array.Reverse(value);
            return value;
        }

        //long转字节数组，默认小端，ldc 20210506
        public static byte[] LongToByte(long data)
        {
            byte[] value = BitConverter.GetBytes(data);
            return value;
        }

        // 字节数组转成short，小端 ldc。short数据类型是16位、有符号的以二进制补码表示的整数，占2字节
        public static short ByteToShort(byte[] data)
        {
            short value = BitConverter.ToInt16(data, 0);
            return value;
        }

         //字节数组转成short，大端 ldc
        public static short ByteToShortBigEndian(byte[] data)
        {
            Array.Reverse(data);
            short value = BitConverter.ToInt16(data, 0);
            return value;
        }

        //short转字节数组，默认小端，ldc 20210506
        public static byte[] ShortToByte(short data)
        {
            byte[] value = BitConverter.GetBytes(data);
            return value;
        }

        //short转字节数组，大端，ldc 20210506
        public static byte[] ShortToByteBigEndian(short data)
        {
            byte[] value = BitConverter.GetBytes(data);
            Array.Reverse(value);
            return value;
        }

         //byte数组转IP格式，针对特定byte数组的处理
        public static string ByteToFormatIp(byte[] bytes)
        {
            string result = "";
            foreach (byte b in bytes)
            {
                result += "." + b.ToString();
            }
            result = result.Substring(1);
            return result;
        }

        //字节数组转8位uint，uint8 数据类型是8位、有符号的以二进制补码表示的整数，占1字节，返回二进制对应的8位整型数值
        public static int ByteToUint8(byte[] data)
        {
            int value = (data[0] & 0xFF);
            return value;
        }

        //字节数组转16位uint，数据类型是16位、有符号的以二进制补码表示的整数，占2字节，默认小端 （已调试）
        public static int ByteToUint16(byte[] data)
        {
            return (data[1] << 8 & 0xFF00 | data[0] & 0xFF);
        }

        //字节数组转16位uint，数据类型是16位、有符号的以二进制补码表示的整数，占2字节，大端
        public static int ByteToUint16BigEndian(byte[] data)
        {
            Array.Reverse(data);
            return (data[0] << 8 & 0xFF00 | data[1] & 0xFF);
        }

        //字节数组转32位uint，数据类型是32位、有符号的以二进制补码表示的整数，占2字节，大端
        public static long ByteToUint32BigEndian(byte[] data)
        {
            Array.Reverse(data);
            return BitConverter.ToUInt32(data,0);
        }

        //字节数组转32位uint，数据类型是32位、有符号的以二进制补码表示的整数，占2字节，默认小端
        public static long ByteToUint32(byte[] data)
        {
            return BitConverter.ToUInt32(data, 0);
        }

        //字节数组转对象 ldc 20210507
        public static object ByteToObject(byte[] data)
        {
            object obj;
            using (MemoryStream ms = new MemoryStream(data))
            {
                IFormatter iFormatter = new BinaryFormatter();
                obj = iFormatter.Deserialize(ms);
            }
            return obj;
        }

        //对象转字节数组 ldc 20210507
        public static object ObjectToByte(Object obj)
        {
            byte[] buff;
            using (MemoryStream ms = new MemoryStream())
            {
                IFormatter iFormatter = new BinaryFormatter();
                iFormatter.Serialize(ms, obj);
                buff = ms.GetBuffer();
            }
            return buff;
        }

        //16字节串转成ipv4地址字符串
        public static string ByteToIp(byte[] data)
        {
            //未实现
            return "";
        }

        //4字节串转成ipv4地址字符串
        public static string FourByteToIp(byte[] data)
        {
            //未实现
            return "";
        }

        //ipv4地址转成字节串 ldc 20210507
        public static byte[] IpToByte(String ipv4)
        {
            byte[] value = new byte[16];
            byte[] realValue = Encoding.UTF8.GetBytes(ipv4);
            Array.Copy(realValue, 0, value, 0, realValue.Length);
            return value;
        }

        /**
         * 未实现 二进制字节串转换成 BitOP 实例
         *
         * @param data: 二进制字节串
         * @return BitOP 实例
         */
        public static double bytesToBitOp(byte[] data)
        {
            // TODO 二进制字节串转换成 BitOP 实例
            return 0.0D;
        }

        /**
         * 未实现 二进制字节串转换成 ByteOp 实例
         *
         * @param data: 二进制字节串
         * @return ByteOp 实例
         */
        public static double bytesToByteOp(byte[] data)
        {
            // TODO 二进制字节串转换成 BitOP 实例
            return 0.0D;
        }

        /**
         * 未实现  二进制字节串转换成 UShortOp 实例
         *
         * @param data: 二进制字节串
         * @return UShortOp 实例
         */
        public static double bytesToUShortOp(byte[] data)
        {
            // TODO 二进制字节串转换成 ByteOp 实例
            return 0.0D;
        }

        /**
         * 未实现  二进制字节串转换成 SingleOp 实例
         *
         * @param data: 二进制字节串
         * @return SingleOp 实例
         */
        public static double bytesToSingleOp(byte[] data)
        {
            // TODO 二进制字节串转换成 SingleOp 实例
            return 0.0D;
        }

        /**
         * 未实现  二进制字节串转换成 Schedule 实例
         *
         * @param data: 二进制字节串
         * @return Schedule 实例
         */
        public static double bytesToSchedule(byte[] data)
        {
            // TODO 二进制字节串转换成 Schedule 实例
            return 0.0D;
        }

        /**
         * 未实现  二进制字节串转换成 AutoMsgCfg 实例
         *
         * @param data: 二进制字节串
         * @return AutoMsgCfg 实例
         */
        public static double bytesToAutoMsgCfg(byte[] data)
        {
            // TODO 二进制字节串转换成 AutoMsgCfg 实例
            return 0.0D;
        }

        /**
         * 未实现  二进制字节串转换成 ContRead 实例
         *
         * @param data: 二进制字节串
         * @return ContRead 实例
         */
        public static byte[] bytesToContRead(byte[] data)
        {
            // TODO 二进制字节串转换成 ContRead 实例
            return data;
        }


        /**
         * 将byte数组转换为一个长度为8*N的byte数组，数组每个值代表bit
         *
         * @param data: 二进制字节串
         * @return 二进制字节串字节字符串
         */
        public static byte[] bytesToBitArray(byte[] data)
        {
            byte[] value = new byte[8 * data.Length];
            int j = 0;
            byte one;
            for(int m = 0; m < data.Length; m++)
            {
                one = data[m];
                for (int i = 0; i <= 7; i++)
                {
                    value[i + j * 8] = (byte)(one & 1);
                    one = (byte)(one >> 1);
                }

                j++;
            }

            return value;
        }





        /**
         * 二进制字节串转换成 Mac 实例
         *
         * @param data: 二进制字节串
         * @return Mac 实例
         */
        public static String bytesToMac(byte[] data)
        {
            StringBuilder stringBuilder = new StringBuilder();

            if (data == null || data.Length <= 0)
            {
                return null;
            }

            for (int i = 0; i < data.Length; i++)
            {
                int value = data[i] & 0xFF;
                String hexValue = value.ToString("X"); //十进制转成十六进制

                if (hexValue.Length< 2)
                {
                    stringBuilder.Append(0);
                }

                stringBuilder.Append(hexValue);

                if (i != 0 && i != 5)
                {
                    stringBuilder.Append(":");
                }
            }

            return stringBuilder.ToString().ToUpper();
        }

        /**
         * 未实现  二进制字节串转换成 MultipathData 实例
         *
         * @param data: 二进制字节串
         * @return MultipathData 实例
         */
        public static double bytesToMultipathData(byte[] data)
        {
            // TODO 二进制字节串转换成 MultipathData 实例
            return 0.0D;
        }

        /**
                 * 将byte数组转为16进制 -分割
                 * isInv为true，则为由高位到低位，否则反之
                 * bytes
                 * isInv 是否倒序
                 */
        public static string byteToHexGap(byte[] data, int start, int end, Boolean isInv)
        {
            byte[] bytes = data.Skip(start).Take(end).ToArray(); //Skip(0)从start位开始，取end位
            string returnStr = "";
            for (int i = 0; i < bytes.Length; i++)
            {
                returnStr += bytes[(isInv ? (bytes.Length - i - 1) : i)].ToString("X2");
            }
            return returnStr;
        }

        /*
         * 将16进制转换成byte数组
         * hexString 16进制字符串
         * isInv 是否倒置输出
         */
        public static byte[] HexTobyte(string hexString, bool isInv)
        {
            hexString = hexString.Replace("0x", "").Replace("0X", "");
            hexString = hexString.Replace(" ", "").Replace("-", "").Replace(":", "").Replace(",", "").Replace("，", "");
            if ((hexString.Length % 2) != 0)
            {
                hexString += " ";
            }
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
            {
                returnBytes[isInv ? (returnBytes.Length - i - 1) : i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
            }
            Console.WriteLine("returnBytes:" + returnBytes);
            return returnBytes;

        }

        /*
         * 读取台站转发站名-编码
         */
        public static String GetStationCode(byte[] data, int start, int end)
        {
            //用户自定义编码
            byte[] tmpBt = data.Skip(start).Take(end).ToArray();//从第三位开始，取16位
            string station_code = Encoding.GetEncoding("utf-8").GetString(tmpBt, 0, tmpBt.Length).ToString();
            station_code = station_code.Substring(0, station_code.IndexOf('\0') > 0 ? station_code.IndexOf('\0') : station_code.Length).Replace("\0", " ").Replace(" ", " ").Trim();
            station_code = station_code.Replace(" ", "");
            return station_code;
        }

        /*
         * byte数组转IP格式，针对特定byte数组的处理
         */
        public static string BytesToFormatIp(byte[] bytes)
        {
            string result = "";
            foreach (byte b in bytes)
            {
                result += "." + b.ToString();
            }
            result = result.Substring(1);
            return result;
        }

        /**
         * byte[]转int，转换与IntToByteArray配合使用
         * isZero为true，则保留空位，否则反之
         * isInv为true，则为由高位到低位，否则反之
         * bytes
         */
        public static int ByteArrayToInt(byte[] bytes, Boolean isInv, Boolean isZero)
        {
            int value = 0;
            for (int i = 0; i < bytes.Length; i++)
            {
                int shift = (isInv ? (3 - i - (isZero ? 0 : (4 - bytes.Length))) : i) * 8;
                value += (bytes[i] & 0xFF) << shift;
            }
            return value;
        }

        /*
         * byte[]转long
         */
        public static long BytesToLong(byte[] buf, bool asc)
        {
            long r = 0;
            if (asc)
            {
                for (int i = 0; i < buf.Length; i++)
                {
                    r <<= 8;
                    r |= (buf[i] & 0x00000000000000ff);
                }
            }
            else
            {
                for (int i = buf.Length - 1; i >= 0; i--)
                {
                    r <<= 8;
                    r |= (buf[i] & 0x00000000000000ff);
                }
            }
            return r;
        }
    }
}
